#include "Uart.h"
#include "Protocol.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <QSocketNotifier>
#include <QFile>
#include <QTimer>
#include <QThread>
#include <QMutexLocker>
#include <unistd.h>
#include <QDebug>

#define DEVICE_FILE     "/dev/ttyS0"

Uart* Uart::getInstance()
{
    static Uart singleton{};
    return &singleton;
}

void Uart::init()
{
    open();
    if (this->uartFd == -1)
        return;
    this->readNotifier = new QSocketNotifier(this->uartFd, QSocketNotifier::Read, this);
    connect(this->readNotifier, &QSocketNotifier::activated, this, &Uart::readDataSlot);
    qDebug()<<"init uart succeed:"<<DEVICE_FILE;
}

void Uart::readDataSlot(int32_t)
{
    static uint8_t buffer[FRAME_MAX_LENGTH];
    QByteArray tmp;
    uint16_t size = 0;

    if (this->uartFd == -1) {
        qDebug()<<"handler: uart fd is -1";
        return;
    }
    readBytes(this->uartFd, buffer, 9);

    size = buffer[7];
    size = size << 8 | buffer[8];
    readBytes(this->uartFd, &buffer[9], size + 5);
    size = 12 + size + 2;
    for (int16_t i = 0; i < size; i++) {
        tmp.append(buffer[i]);
    }
    qDebug()<<"handler: size = "<<size<<" rec:"<<tmp.toHex();
    Protocol::getInstance()->parse(buffer);
}

void Uart::open()
{
    this->uartFd = ::open(DEVICE_FILE, O_RDWR | O_NOCTTY | O_CLOEXEC);
    if (this->uartFd == -1) {
        qCritical() << DEVICE_FILE << "open failed:" << errno;
        return;
    }
    if (!::isatty(this->uartFd)) {
        qCritical() << DEVICE_FILE << "is not a tty";
        ::close(this->uartFd);
        this->uartFd = -1;
        return;
    }
    if (::tcgetattr(this->uartFd, &this->oldConfig) == -1) {
        qCritical() << DEVICE_FILE << "tcgetattr failed:" << errno;
        ::close(this->uartFd);
        this->uartFd = -1;
        return;
    }

    /* config serial port */
    this->config = this->oldConfig;
    this->config.c_cflag |= CLOCAL | CREAD;
    cfmakeraw(&this->config);
    this->config.c_cflag &= ~CSIZE;

    /* speed */
    cfsetispeed(&this->config, B115200);
    cfsetospeed(&this->config, B115200);

    /* data bits */
    this->config.c_cflag |= CS8;

    /* parity */
    this->config.c_cflag &= ~PARENB;
    this->config.c_iflag &= ~INPCK;

    /* stop bits */
    this->config.c_cflag &= ~CSTOPB;

    /* other config*/
    this->config.c_cc[VTIME] = 0;
    this->config.c_cc[VMIN] = 1;
    ::tcflush(this->uartFd, TCIFLUSH);

    if(::tcsetattr(this->uartFd, TCSANOW, &this->config) == -1) {
        qCritical() << DEVICE_FILE << "tcsetattr failed" << errno;
        ::close(this->uartFd);
        this->uartFd = -1;
    }
}

void Uart::sendData(u_int8_t* buffer, int32_t length)
{
    QString data;

    for (int i = 0; i < length; i++) {
        data.append(buffer[i]);
    }
    ::write(this->uartFd, buffer, length);
    if (buffer[6] == 0x14 ||buffer[6] == 0x0E || buffer[6] == 0x17)
        return;
    qDebug()<<"handler: send, "<<data.toLatin1().toHex();
}

void Uart::readBytes(int fd, unsigned char *buf, int n)
{
    for (int count = 0;count != n;) {
        int tmp = ::read(fd, &buf[count], n - count);
        if (tmp != -1)
            count += tmp;
    }
}
